package stmdao

import (
	"strings"
	"wzgames/internal/gdao"
	"wzgames/internal/model/statement"
	"wzgames/internal/response"
)

type StmDao gdao.DaoSource

const sqlQueryStatementsByVer = "select a.id,a.bettime,a.vidx,b.roundid,b.currid,b.gameid,b.inst,b.curr,b.freebet,b.betamt,b.winamt,b.effamt,b.fee,b.payout,b.paytime,b.details,b.status,b.uname,b.agtuid from bet_ver a inner join bet_history b on a.id=b.id where a.agtid=? and a.vidx>? order by a.vidx asc limit ?"

func (dao *StmDao) GetStatementsByVer(agtId int64, ver uint64, limit int32) ([]*statement.BetResult, error) {
	rows, err := dao.Queryx(sqlQueryStatementsByVer, agtId, ver, limit)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*statement.BetResult
	for rows.Next() {
		rd := &statement.BetResult{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		rd.BetAmt = response.TrimAmtZeros(rd.BetAmt)
		rd.EffAmt = response.TrimAmtZeros(rd.EffAmt)
		rd.WinAmt = response.TrimAmtZeros(rd.WinAmt)
		rd.Fee = response.TrimAmtZeros(rd.Fee)
		ret = append(ret, rd)
	}
	return ret, err
}

const sqlQueryStatementsByStamp = "select a.id,a.bettime,a.vidx,b.roundid,b.currid,b.gameid,b.inst,b.curr,b.freebet,b.betamt,b.winamt,b.effamt,b.fee,b.payout,b.paytime,b.details,b.status,b.uname,b.agtuid from bet_ver a inner join bet_history b on a.id=b.id where a.agtid=?  and a.bettime>=? and a.bettime<=? and a.vidx>? order by a.vidx asc limit ?"

func (dao *StmDao) GetStatementsByStamp(agtId, st, et int64, ver uint64, limit int32) ([]*statement.BetResult, error) {
	rows, err := dao.Queryx(sqlQueryStatementsByStamp, agtId, st, et, ver, limit)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*statement.BetResult
	for rows.Next() {
		rd := &statement.BetResult{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		rd.BetAmt = response.TrimAmtZeros(rd.BetAmt)
		rd.EffAmt = response.TrimAmtZeros(rd.EffAmt)
		rd.WinAmt = response.TrimAmtZeros(rd.WinAmt)
		rd.Fee = response.TrimAmtZeros(rd.Fee)
		ret = append(ret, rd)
	}
	return ret, err
}

const sqlCreateBet = "insert into bet_history(`id`,`roundid`,`uid`,`agtid`,`currid`,`inst`,`gameid`,`curr`,`freebet`,`win`,`betamt`,`effamt`,`winamt`,`payout`,`fee`,`bettime`,`paytime`,`details`,`status`,`uname`,`agtuid`,`gact`,`op`,`nodeid`,`created`,`updated`)" +
	" values(:id,:roundid,:uid,:agtid,:currid,:inst,:gameid,:curr,:freebet,:win,:betamt,:effamt,:winamt,:payout,:fee,:bettime,:paytime,:details,:status,:uname,:agtuid,:gact,:op,:nodeid,:created,:updated) on duplicate key update updated=values(updated)"

func (dao *StmDao) CreateBet(data *statement.BetResult) error {
	_, err := dao.NamedExec(sqlCreateBet, data)
	return err
}

func (dao *StmDao) CreateBetBatch(data []*statement.BetResult) error {
	_, err := dao.NamedExec(sqlCreateBet, data)
	return err
}

const sqlCreateInputData = "insert into play_input_data(`uid`,`dateline`,`nodeid`,`currid`,`inst`,`gameid`,`betid`,`gact`,`roundid`,`precision`,`ckcode`,`balance`,`data`)" +
	" values(:uid,:dateline,:nodeid,:currid,:inst,:gameid,:betid,:gact,:roundid,:precision,:ckcode,:balance,:data) on duplicate key update gact=values(gact)"

func (dao *StmDao) CreateInputData(data *statement.PlayInputData) error {
	_, err := dao.NamedExec(sqlCreateInputData, data)
	return err
}

const sqlCreatePlayBet = "insert into play_bets(`id`,`roundid`,`uid`,`nodeid`,`agtid`,`currid`,`inst`,`gameid`,`precision`,`curr`,`freebet`,`betamt`,`effamt`,`fee`,`bettime`,`details`,`uname`,`agtuid`,`gcid`,`created`,`updated`)" +
	" values(:id,:roundid,:uid,:nodeid,:agtid,:currid,:inst,:gameid,:precision,:curr,:freebet,:betamt,:effamt,:fee,:bettime,:details,:uname,:agtuid,:gcid,:created,:updated) on duplicate key update `updated`=values(updated)"

func (dao *StmDao) CreatePlayBet(data *statement.PlayBetEnt) error {
	_, err := dao.NamedExec(sqlCreatePlayBet, data)
	return err
}

const sqlCreateBetPayout = "insert into play_payouts(`id`,`roundid`,`gact`,`win`,`winamt`,`payout`,`paytime`,`op`,`details`,`created`,`updated`)" +
	" values(:id,:roundid,:gact,:win,:winamt,:payout,:paytime,:op,:details,:created,:updated) on duplicate key update `updated`=values(updated)"

func (dao *StmDao) CreateBetPayout(data *statement.PlayPayoutEnt) error {
	_, err := dao.NamedExec(sqlCreateBetPayout, data)
	return err
}

const sqlCreateBetCancel = "insert into play_cancels(`id`,`op`,`dateline`) values(:id,:op,:dateline) on duplicate key update `op`=values(op)"

func (dao *StmDao) CreateBetCancel(data *statement.PlayCancelEnt) error {
	_, err := dao.NamedExec(sqlCreateBetCancel, data)
	return err
}

const sqlCreateBetStep = "insert into play_steps(`id`,`roundid`,`win`,`winamt`,`payout`,`dateline`,`details`)" +
	" values(:id,:roundid,:win,:winamt,:payout,:dateline,:details) on duplicate key update `dateline`=values(dateline)"

func (dao *StmDao) CreateBetStep(data *statement.PlayStepEnt) error {
	_, err := dao.NamedExec(sqlCreateBetStep, data)
	return err
}

const sqlGetPlayBet = "select * from play_bets where `id`=? limit 1"

func (dao *StmDao) GetPlayBet(id uint64) (*statement.PlayBetEnt, error) {
	r := &statement.PlayBetEnt{}
	err := dao.Get(r, sqlGetPlayBet, id)
	return r, err
}

const sqlGetPlayPayout = "select * from play_payouts where `id`=? limit 1"

func (dao *StmDao) GetPlayPayout(id uint64) (*statement.PlayPayoutEnt, error) {
	r := &statement.PlayPayoutEnt{}
	err := dao.Get(r, sqlGetPlayPayout, id)
	return r, err
}

const sqlGetPlayCancel = "select * from play_cancels where `id`=? limit 1"

func (dao *StmDao) GetPlayCancel(id uint64) (*statement.PlayCancelEnt, error) {
	r := &statement.PlayCancelEnt{}
	err := dao.Get(r, sqlGetPlayCancel, id)
	return r, err
}

const sqlGetPlayMaxStep = "select * from play_steps where `id`=? order by `roundid` desc limit 1"

func (dao *StmDao) GetPlayMaxStep(id uint64) (*statement.PlayStepEnt, error) {
	r := &statement.PlayStepEnt{}
	err := dao.Get(r, sqlGetPlayMaxStep, id)
	return r, err
}

const sqlGetPlaySteps = "select * from play_steps where `id`=? order by `roundid` asc"

func (dao *StmDao) GetPlaySteps(id uint64) ([]*statement.PlayStepEnt, error) {
	rows, err := dao.Queryx(sqlGetPlaySteps, id)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*statement.PlayStepEnt
	for rows.Next() {
		rd := &statement.PlayStepEnt{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		ret = append(ret, rd)
	}
	return ret, err
}

const sqlGetPlayInput = "select * from play_input_data where `uid`=? and `dateline`=? limit 1"

func (dao *StmDao) GetPlayInput(uid uint64, dateline int64) (*statement.PlayInputData, error) {
	r := &statement.PlayInputData{}
	err := dao.Get(r, sqlGetPlayInput, uid, dateline)
	return r, err
}

const sqlGetPlayInputs = "select * from play_input_data where `uid`=?"

func (dao *StmDao) GetPlayInputs(uid uint64, start, end int64, betId uint64, limit int64) ([]*statement.PlayInputData, error) {
	var sb strings.Builder
	var items []string
	var args []interface{}
	sb.WriteString(sqlGetPlayInputs)
	args = append(args, uid)
	if start > 0 {
		items = append(items, " `dateline`>=? ")
		args = append(args, start)
	}
	if end > 0 {
		items = append(items, " `dateline`<=? ")
		args = append(args, end)
	}
	if betId > 0 {
		items = append(items, " `betid`=? ")
		args = append(args, betId)
	}
	if len(items) > 0 {
		sb.WriteString(" and ")
		sb.WriteString(strings.Join(items, " and "))
	}
	sb.WriteString(" order by `dateline` desc limit ?")
	args = append(args, limit)
	rows, err := dao.Queryx(sb.String(), args...)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*statement.PlayInputData
	for rows.Next() {
		rd := &statement.PlayInputData{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		ret = append(ret, rd)
	}
	return ret, err
}

const sqlGetPlayBetIn = "select * from play_bets where `id` in("

func (dao *StmDao) GetPlayBetIn(ids string) (map[uint64]*statement.PlayBetEnt, int, error) {
	var sqlTmp = sqlGetPlayBetIn + ids + ")"
	rows, err := dao.Queryx(sqlTmp)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, 0, err
	}
	ret := make(map[uint64]*statement.PlayBetEnt)
	c := 0
	for rows.Next() {
		rd := &statement.PlayBetEnt{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, 0, err
		}
		ret[rd.BetId] = rd
		c++
	}
	return ret, c, err
}

func (dao *StmDao) GetPlayBetInToArr(ids string) ([]*statement.PlayBetEnt, int, error) {
	var sqlTmp = sqlGetPlayBetIn + ids + ")"
	rows, err := dao.Queryx(sqlTmp)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, 0, err
	}
	var ret []*statement.PlayBetEnt
	c := 0
	for rows.Next() {
		rd := &statement.PlayBetEnt{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, 0, err
		}
		ret = append(ret, rd)
		c++
	}
	return ret, c, err
}

const sqlGetPlayPayoutIn = "select * from play_payouts where `id` in("

func (dao *StmDao) GetPlayPayoutIn(ids string) (map[uint64]*statement.PlayPayoutEnt, int, error) {
	var sqlTmp = sqlGetPlayPayoutIn + ids + ")"
	rows, err := dao.Queryx(sqlTmp)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, 0, err
	}
	ret := make(map[uint64]*statement.PlayPayoutEnt)
	c := 0
	for rows.Next() {
		rd := &statement.PlayPayoutEnt{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, 0, err
		}
		ret[rd.BetId] = rd
		c++
	}
	return ret, c, err
}

const sqlUpdateBetVer = "update bet_ver set `vidx`=? where `id`=?"

func (dao *StmDao) UpdateBetVIdx(vidx uint64, id int64) (int64, error) {
	result, err := dao.Exec(sqlUpdateBetVer, vidx, id)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlQueryZeroVIdx = "select a.id,a.agtid,a.bettime from bet_history a left join bet_ver b on a.id=b.id where b.id is null order by a.bettime asc limit ?"

func (dao *StmDao) GetStatementsZeroVIdx(limit int32) ([]*statement.StmVerIdx, error) {
	var bets []*statement.StmVerIdx
	err := dao.Select(&bets, sqlQueryZeroVIdx, limit)
	return bets, err
}

const sqlInsertZeroVIdx = "insert into bet_ver(`id`,`agtid`,`bettime`,`vidx`) values(:id,:agtid,:bettime,:vidx) on duplicate key update vidx=values(vidx)"

func (dao *StmDao) InsertStatementsZeroVIdx(data []*statement.StmVerIdx) (int64, error) {
	result, err := dao.NamedExec(sqlInsertZeroVIdx, data)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlQueryStatementsByLimit = "select `id`,`bettime`,`roundid`,`curr`,`freebet`,`win`,`betamt`,`winamt`,`effamt`,`fee`,`payout`,`paytime`,`details` from bet_history where `uid`=? and `inst`=? and `currid`=? and `status`=1 order by `bettime` desc limit ?,?"

func (dao *StmDao) GetStatementsByLimit(uid uint64, instId, offset, limit int64, currId int32) ([]*statement.BetResultSimple, error) {
	rows, err := dao.Queryx(sqlQueryStatementsByLimit, uid, instId, currId, offset, limit)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*statement.BetResultSimple
	for rows.Next() {
		rd := &statement.BetResultSimple{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		rd.BetAmt = response.TrimAmtZeros(rd.BetAmt)
		rd.EffAmt = response.TrimAmtZeros(rd.EffAmt)
		rd.WinAmt = response.TrimAmtZeros(rd.WinAmt)
		rd.Fee = response.TrimAmtZeros(rd.Fee)
		ret = append(ret, rd)
	}
	return ret, err
}

const sqlGetDoneStatement = "select `id`,`bettime`,`roundid`,`curr`,`freebet`,`win`,`betamt`,`winamt`,`effamt`,`fee`,`payout`,`paytime`,`details` from bet_history where `id`=? and `uid`=? limit 1"

func (dao *StmDao) GetStatementDone(id, uid uint64) (*statement.BetResultSimple, error) {
	r := &statement.BetResultSimple{}
	err := dao.Get(r, sqlGetDoneStatement, id, uid)
	if r != nil {
		r.BetAmt = response.TrimAmtZeros(r.BetAmt)
		r.EffAmt = response.TrimAmtZeros(r.EffAmt)
		r.WinAmt = response.TrimAmtZeros(r.WinAmt)
		r.Fee = response.TrimAmtZeros(r.Fee)
	}
	return r, err
}
